/*
 * 枚举
 * `enum`关键字允许创建一个从数个不同取值中选其一的枚举类型。任何一个在`struct`中
 * 合法的取值在`enum`中也合法
 */
// 该属性用于隐藏对未使用代码的警告
#![allow(dead_code)]

// 创建一个`enum`来对web事件分类。注意变量名和类型共同指定了`enum`取值的种类
// `PageLoad`不等于`PageUnload`，`KeyPress(char)`不等于`Paste(String)`。
// 各个取值不同，互相独立
enum WebEvent {
    // 一个`enum`可以是单元结构体(称为`unit-like`或`unit`)
    PageLoad,
    PageUnload,
    // 或一个元组结构体
    KeyPress(char),
    Paste(String),
    // 或者一个普通的结构体
    Click {x: i64, y: i64 }
}

// 此函数将一个`WebEvent` enum 作为参数，无返回值
fn inspect(event: WebEvent) {
    match event {
        WebEvent::PageLoad => println!("page loaded"),
        WebEvent::PageUnload => println!("page unloaded"),
        // 从`enum`里解构出`c`
        WebEvent::KeyPress(c) => println!("pressed '{}'", c),
        WebEvent::Paste(s) => println!("pasted \"{}\"", s),
        // 把`Click`解构给`x` and `y`
        WebEvent::Click {x, y} => {
            println!("clicked at x = {}, y = {}", x, y);
        },
    }
}

// 类型别名
// 若使用类型别名，可以通过其别名引用每个枚举变量。
// 当枚举的名称太长或者太一般话，且你想对其重命名，就可以使用类型别名
enum VeryVerboseEnumOfThingsToDoWithNumbers {
    Add,
    Subtract,
}

// 创建一个类型别名
type Operations = VeryVerboseEnumOfThingsToDoWithNumbers;

// 最常见的情况是在impl 块中使用 `Self` 别名
impl VeryVerboseEnumOfThingsToDoWithNumbers {
    fn run(&self, x: i32, y: i32) -> i32 {
        match self {
            Self::Add => x + y,
            Self::Subtract => x - y,
        }
    }
}

fn main() {
    let pressed = WebEvent::KeyPress('x');
    // `to_owned()` 从一个字符串切片中创建一个具有所有权的`String`
    let pasted = WebEvent::Paste("my test".to_owned());
    let click = WebEvent::Click {x: 20, y: 80};
    let load = WebEvent::PageLoad;
    let unload = WebEvent::PageUnload;

    inspect(pressed);
    inspect(pasted);
    inspect(click);
    inspect(load);
    inspect(unload);

    // 通过别名引用枚举变量，避免使用又长又不方便的名子
    let x = Operations::Add;
}